package cn.iocoder.yudao.common.util.date;

import cn.hutool.core.date.LocalDateTimeUtil;
import org.springframework.lang.Nullable;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * 时间工具类
 */
public class DateUtils {
    private static final DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter HHmmss = DateTimeFormatter.ofPattern("HH:mm:ss");
    private static final DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    /**
     * 时区 - 默认
     */
    public static final String TIME_ZONE_DEFAULT = "GMT+8";

    /**
     * 秒转换成毫秒
     */
    public static final long SECOND_MILLIS = 1000;

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";

    public static LocalDate dateTolLocalDate(@Nullable Date date) {

        if (date == null) {
            return null;
        }

        return dateToZonedDateTime(date).toLocalDate();
    }

    public static Date localDateToDate(@Nullable LocalDate localDate) {

        if (localDate == null) {
            return null;
        }

        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    public static Date localDateTimeToDate(@Nullable LocalDateTime localDateTime) {

        if (localDateTime == null) {
            return null;
        }

        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public static LocalDateTime dateToLocalDateTime(@Nullable Date date) {

        if (date == null) {
            return null;
        }

        return dateToZonedDateTime(date).toLocalDateTime();
    }

    /**
     * @param localDate 时间
     * @return 2023-07-05 00:00:00
     */
    public static Date localDateToDateMin(@Nullable LocalDate localDate) {

        if (localDate == null) {
            return null;
        }

        return Date.from(LocalDateTime.of(localDate, LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant());

    }

    /**
     * @param localDate 时间
     * @return 2023-07-05 23:59:59
     */
    public static Date localDateToDateMax(@Nullable LocalDate localDate) {

        if (localDate == null) {
            return null;
        }

        return Date.from(LocalDateTime.of(localDate, LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());

    }

    private static ZonedDateTime dateToZonedDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault());
    }

    /**
     * @param date 时间
     * @return date开始时间 2023-07-05 00:00:00
     */
    public static Date getEndOfDay(@Nullable Date date) {
        if (date == null) {
            return null;
        }
        return localDateToDateMax(dateTolLocalDate(date));
    }


    /**
     * @param date 时间
     * @return date开始时间 2023-07-05 23:59:59
     */
    public static Date getStartOfDay(@Nullable Date date) {
        if (date == null) {
            return null;
        }
        return localDateToDateMin(dateTolLocalDate(date));
    }


    @Deprecated
    public static Date addTime(Duration duration) {
        return new Date(System.currentTimeMillis() + duration.toMillis());
    }

    /**
     * @param time 时间
     * @return 判断是否过期
     */
    public static boolean isExpired(Date time) {
        return System.currentTimeMillis() > time.getTime();
    }

    /**
     * @param time 时间
     * @return 判断是否过期
     */
    public static boolean isExpired(LocalDateTime time) {
        LocalDateTime now = LocalDateTime.now();
        return now.isAfter(time);
    }

    /**
     * 计算两个日期之间的时间差（以毫秒为单位）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 时间差
     */
    public static long diff(Date startTime, Date endTime) {
        // 使用getTime()方法获取日期的毫秒表示，然后计算时间差
        return endTime.getTime() - startTime.getTime();
    }

    /**
     * 返回两个日期中较大的日期
     *
     * @param a 日期a
     * @param b 日期b
     * @return 较大的日期，如果有一个日期为null，则返回另一个日期；如果两个日期相等，则返回任意一个日期
     */
    public static Date max(Date a, Date b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }

        // 使用compareTo方法比较两个日期的大小，返回较大的日期
        return a.compareTo(b) > 0 ? a : b;
    }

    /**
     * 返回两个LocalDateTime中较大的日期时间
     *
     * @param a LocalDateTime对象a
     * @param b LocalDateTime对象b
     * @return 较大的日期时间，如果有一个日期时间为null，则返回另一个日期时间；如果两个日期时间相等，则返回任意一个日期时间
     */
    public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        // 使用isAfter方法比较两个日期时间的先后关系，返回较大的日期时间
        return a.isAfter(b) ? a : b;
    }


    /**
     * 是否今天
     *
     * @param date 日期
     * @return 是否
     */
    public static boolean isToday(LocalDateTime date) {
        return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
    }


    public static Date parseDateyyyyMMdd(String str) {
        return parseDate(str, yyyyMMdd);
    }

    public static Date parseDateyyyyMMddHHmmss(String str) {
        return parseDate(str, yyyyMMddHHmmss);
    }

    public static Date parseDateHHmmss(String str) {
        return parseDate(str, HHmmss);
    }

    public static Date parseDate(String str, DateTimeFormatter formatter) {

        if (str == null || str.isEmpty()) {
            throw new IllegalArgumentException("str 不能为空");
        }

        if (formatter == null) {
            throw new IllegalArgumentException("pattern 不能为空");
        }
        return localDateTimeToDate(LocalDateTime.parse(str, formatter));

    }

}
